# 作者： 李泉志
# 2025年01月09日15时28分秒
# 2947029073@qq.com

"""
9 类属性和类方法
目标
• 类的结构
• 类属性和实例(对象)属性
• 类方法和静态方法

01. 类的结构
1.1 术语 —— 实例
1)使用面向对象开发，第1步是设计类
2)使用 类名() 创建对象，创建对象的动作有两步：
    – 在内存中为对象分配空间
    – 调用初始化方法 __init__ 为对象初始化
3)对象创建后，内存中就有了一个对象的实实在在的存在 —— 实例

02. 类属性和实例属性
2.1 概念和使用
• 类属性就是给类对象中定义的属性
• 通常用来记录与这个类相关的特征
• 类属性不会用于记录具体对象的特征

2.2 属性的获取机制（科普）
• 在Python中属性的获取存在一个向上查找机制
    1) 首先在对象中查找是否有该属性
    2) 如果没有，则向上查找类属性
• 因此，要访问类属性有两种方式：
    1) 类名.类属性
    2) 对象.类属性 （不推荐）
• 如果使用 对象.类属性 = 值 赋值语句，只会给对象添加一个属性，而不会影响到类属性的值

03. 类方法和静态方法（使用不频繁）
3.1 类方法
• 类属性就是针对类对象定义的属性
    – 使用赋值语句在 class 关键字下方可以定义类属性
    – 类属性用于记录与这个类相关的特征
• 类方法就是针对类对象定义的方法
    – 在类方法内部可以直接访问类属性或者调用其他的类方法
语法如下：
@classmethod
def 类方法名(cls):
    pass
• 类方法需要用 修饰器@classmethod 来标识，告诉解释器这是一个类方法
• 类方法的第一个参数应该是 cls
    – 由哪一个类调用的方法，方法内的 cls 就是哪一个类的引用
    – 这个参数和实例方法的第一个参数是 self 类似
    – 使用其他名称也可以，不过习惯使用 cls
• 通过类名. 调用类方法，调用方法时，不需要传递 cls 参数
• 在方法内部
    – 可以通过 cls. 访问类的属性
    – 也可以通过 cls. 调用其他的类方法

3.2 静态方法
• 在开发时，如果需要在类中封装一个方法，这个方法：
– 既不需要访问实例属性或者调用实例方法
– 也不需要访问类属性或者调用类方法
• 这个时候，可以把这个方法封装成一个静态方法，例如打印一些帮助
语法如下
@staticmethod
def 静态方法名():
    pass
• 静态方法需要用修饰器 @staticmethod 来标识，告诉解释器这是一个静态方法
• 通过 类名. 调用 静态方法，虽然可以通过 对象.静态方法 来执行，但是不规范
"""


class Tool(object):
    count = 0  # 类属性，记录创建工具对象的总数

    def __init__(self, name):
        self.name = name
        # 针对类属性做一个计数+1
        Tool.count += 1

    def func(self):
        print(f'{self.name} 工具使用中...')

    @classmethod
    def show_count(cls):  # 类方法
        """
        当不使用对象属性，只使用类属性，给类增加类属性
        :return:
        """
        print(cls.count)  # cls就是当前类名，即Tool

    @staticmethod
    def print_help():  # 静态方法
        """
        既不用对象属性，也不用类属性
        :return:
        """
        print("帮助信息...")

if __name__ == '__main__':
    t1 = Tool('斧头')
    print(Tool.count)
    t2 = Tool('锤子')
    print(Tool.count)
    # print(t2.count)  # 也对，count相当于类的全局变量，但不推荐
    t2.count = 99  # 不会影响到类属性的值，只会给对象添加一个属性
    print("工具对象总数 %d" % t2.count)  # 99
    print("===> %d" % Tool.count)  # 还是2
    print('-'*50)
    Tool.show_count()  # 2 虽然可以通过对象.类方法，但是不规范
    Tool.print_help()  #
